package cn.lpq.manage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import cn.lpq.pojo.HeikeyunAccount;
import cn.lpq.util.OcrCaptchaUtil;

@Component
public class HeikeyunManage implements CommandLineRunner {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	// 注册用的锁
	private Object regLock = new Object();

	// 最大注册帐号数量
	@Value("${heikeyun.maxRegUserNum}")
	public int maxRegUserNum;
	// 保持在线用的cookie
	public static Map<String, HeikeyunAccount> cookieMap = new LinkedHashMap<String, HeikeyunAccount>();
	// 储存所有帐号
	public static List<HeikeyunAccount> heikeyunAccounts = Collections
			.synchronizedList(new ArrayList<HeikeyunAccount>());
	// 可下载帐号
	public static List<HeikeyunAccount> canDownloadAccounts = Collections
			.synchronizedList(new ArrayList<HeikeyunAccount>());

	/**
	 * 磁力解析
	 * 
	 * @param magnet 磁力链接
	 */
	public List<Map<String, String>> parseMagnet(String magnet, File torrentFile) {
		logger.debug("待解析的磁力链接：" + magnet);
		logger.debug("待解析的种子：{}", torrentFile);
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		if (!cookieMap.keySet().iterator().hasNext()) {
			logger.debug("没有账号可供下载,重新注册几个");
			reg();
		}
		String cookie = cookieMap.keySet().iterator().next();
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			// 把一个普通参数和文件上传给下面这个地址 是一个servlet
			HttpPost httpPost = new HttpPost("http://lx.heikeyun.net/Main.aspx");
			httpPost.addHeader("Host", "lx.heikeyun.net");
			httpPost.addHeader("Cookie", cookie);

			StringBody strEmpty = new StringBody("", ContentType.create("text/plain", Consts.UTF_8));
//			StringBody viewstate = new StringBody(
//					"x//g3MPKxwaJvsNZYoQHgIfNLs3A6A4vWdEXbmLVRlwY/8KnS7ctFcSKnDBEgTDoscBPzFkz0qdQqOCFgjgEb69FP490KP7LTT5i2TytsE/Wam7vHKh0dVCdwBx5o2p1Z0b5QNOKMo4/RWMr94tYlQGMyWmWdzlXrGOIg80pj+AWwpbqVqcraAsH6UAaSDxGbxGSkwqRJY2JOFdEWxExWOnAEu4q5b/rzNBYHkKb9LfwVu7atqR2/vvub9NwBcyps74JFXx3sWy8bPDrJCa3klY1SgjRG8rgiKcNXKu+dvx/v6Xe4q4qH6pGI7C/PA1qCVCew6953ic+IiL3",
//					ContentType.create("text/plain", Consts.UTF_8));
			StringBody txtBtHash = new StringBody(magnet, ContentType.create("text/plain", Consts.UTF_8));
			StringBody btnGoHash = new StringBody("解析", ContentType.create("text/plain", Consts.UTF_8));

			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			FileBody bin;
			if (torrentFile == null) {
				bin = new FileBody(File.createTempFile(System.getProperty("java.io.tmpdir"), null));
				builder.addPart("ctl00$ContentPlaceHolder1$btnGoHash", btnGoHash);
			} else {
				bin = new FileBody(torrentFile);
				builder.addPart("ctl00$ContentPlaceHolder1$btnTorrent", btnGoHash);
			}
			// 相当于<input type="file" name="file"/>
			builder.addPart("ctl00$ContentPlaceHolder1$FileOpenTorrent", bin)
					// 相当于<input type="text" name="userName" value=userName>
					.addPart("__EVENTTARGET", strEmpty).addPart("__EVENTARGUMENT", strEmpty)
					.addPart("__VIEWSTATE", strEmpty).addPart("ctl00$ContentPlaceHolder1$txtBtHash", txtBtHash);

			HttpEntity reqEntity = builder.build();
			httpPost.setEntity(reqEntity);

			// 发起请求 并返回请求的响应
			response = httpClient.execute(httpPost);
			// 处理重定向
			String locationUrl = response.getLastHeader("Location").getValue();
			HttpGet httpget = new HttpGet("http://lx.heikeyun.net/" + locationUrl);
			httpget.addHeader("Cookie", cookie);
			response = httpClient.execute(httpget);
			HttpEntity entity = response.getEntity(); // 获取网页内容
			String html = EntityUtils.toString(entity, "UTF-8");
			Document doc = Jsoup.parse(html);
			Elements links = doc.select("a[ck]");
			for (Element link : links) {
				String data = link.attr("data");
				String s1 = link.attr("s1");
				String fileSize = link.select("small").text();
				StringBuffer fileName = new StringBuffer();
				String[] fileNameArr = link.select("span").text().split("·");
				// 解密文件名字符
				for (int i = 0; i < fileNameArr.length; i++) {
					fileNameArr[i] = fileNameArr[i].substring(1);
					fileNameArr[i] = fileNameArr[i].substring(0, fileNameArr[i].length() - 1);
					fileName.append((char) Integer.parseInt(fileNameArr[i]));
				}
				fileName = new StringBuffer(utf8to16(fileName.toString()));

				Map<String, String> map = new HashMap<String, String>();
				map.put("fileName", fileName.toString());
				map.put("fileSize", fileSize);
				map.put("data", data);
				map.put("s1", s1);
				result.add(map);
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("解析发生错误！！！");
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * 返回文件的真实下载地址
	 * 
	 * @param data 加密的文件信息
	 * @param s1   好像是文件名
	 * @return 真实下载地址
	 */
	public String download(String data, String s1) {
		// synchronized (cookieMap) {
		if (!cookieMap.keySet().iterator().hasNext()) {
			logger.debug("没有账号可供下载,重新注册几个");
			reg();
		}
		String cookie = cookieMap.keySet().iterator().next();
		// 如果这个帐号已经下载4个了 那么下载完这个 这个帐号今天就没用了
		HeikeyunAccount account = cookieMap.get(cookie);
		account.setDownloadCount(account.getDownloadCount() + 1);
		if (account.getDownloadCount() == account.getMaxDownloadCount()) {
			cookieMap.remove(cookie);
			canDownloadAccounts.remove(account);
		}
		writeToLocalTxt();
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			HttpPost httpPost = new HttpPost("http://lx.heikeyun.net/CommonAjax.ashx?type=DownUrl");
			httpPost.addHeader("Cookie", cookie);
			httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
			Map<String, String> param = new HashMap<String, String>();
			param.put("d", data);
			param.put("s1", s1);
			param.put("tp", "web");
			String jsonstr = JSONUtil.toJsonStr(param);
			StringEntity se = new StringEntity(jsonstr);
			httpPost.setEntity(se);
			response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity(); // 获取网页内容
			Map result = JSONUtil.toBean(EntityUtils.toString(entity, "UTF-8"), Map.class);
			if (result.get("DownUrl") != null && !result.get("DownUrl").toString().equals("null")) {
				String encodeBase64Url = result.get("DownUrl").toString();
				logger.debug("编码前的地址：" + encodeBase64Url);
				encodeBase64Url = Base64.decodeStr(encodeBase64Url);
				logger.debug("解码后：" + encodeBase64Url);
				return encodeBase64Url;
			} else {
				return null;
			}

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("解析发生错误！！！");
			return null;
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// }

	}

	/**
	 * 根据设置的最大同时注册数量注册几个号,然后登陆
	 */
	public void reg() {
		synchronized (regLock) {
			// 本地有帐号优先用本地的
			for (int i = cookieMap.size(); i < maxRegUserNum; i++) {
				try {
					HeikeyunAccount account = canDownloadAccounts.get(i);
					String cookie = login(account.getAccount(), account.getPassword(), null, 0);
					if (cookie != null) {
						cookieMap.put(cookie, account);
					}
					cookieMap.put(cookie, account);
				} catch (IndexOutOfBoundsException e) {
				}
			}
			for (int i = cookieMap.size(); i < maxRegUserNum; i++) {
				logger.debug("正在尝注册新账号。。。");
				CloseableHttpClient httpClient = null;
				CloseableHttpResponse response = null;
				try {
					httpClient = HttpClients.createDefault();
					Connection.Response execute = Jsoup.connect("http://lx.heikeyun.net/login.aspx")
							.ignoreContentType(true).execute();
					// 获取返回数据
					String body = execute.body();
					// 获取返回cookie
					String cookie = "";
					Map<String, String> cookies = execute.cookies();
					for (String key : cookies.keySet()) {
						cookie += key + "=" + cookies.get(key) + ";";
					}
					Document doc = Jsoup.parse(body);
					String viewstate = doc.select("input[name=__VIEWSTATE]").val();
					String viewstategenerator = doc.select("input[name=__VIEWSTATEGENERATOR]").val();
					String eventvalidation = doc.select("input[name=__EVENTVALIDATION]").val();
					// 保持COOKIE传过去取得验证码
					String txtCode = OcrCaptchaUtil.getYzm(cookie);
					String randomId = RandomUtil.randomString(8);
					HttpPost httpPost = new HttpPost("http://lx.heikeyun.net/login.aspx");
					httpPost.setHeader("Cookie", cookie);
					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("__VIEWSTATE", viewstate));
					nvps.add(new BasicNameValuePair("__VIEWSTATEGENERATOR", viewstategenerator));
					nvps.add(new BasicNameValuePair("__EVENTVALIDATION", eventvalidation));
					nvps.add(new BasicNameValuePair("btnReg", "注   册"));
					nvps.add(new BasicNameValuePair("txtId", ""));
					nvps.add(new BasicNameValuePair("txtPwd", ""));
					nvps.add(new BasicNameValuePair("txtCode", ""));
					nvps.add(new BasicNameValuePair("txtRegUserName", randomId));
					nvps.add(new BasicNameValuePair("txtRegPwd", randomId));
					nvps.add(new BasicNameValuePair("txtRegPwd2", randomId));
					nvps.add(new BasicNameValuePair("txtRegMail", randomId + "@qq.com"));
					nvps.add(new BasicNameValuePair("txtRegCode", txtCode));
					httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
					response = httpClient.execute(httpPost);
					HttpEntity entity = response.getEntity();
					String resultHtml = EntityUtils.toString(entity, "UTF-8");
					if (resultHtml.indexOf("注册成功") != -1) {
						logger.debug("尝试注册成功！！！");
						HeikeyunAccount account = new HeikeyunAccount(randomId, randomId, 0, 5, "否");
						cookieMap.put(cookie, account);
						canDownloadAccounts.add(account);
						heikeyunAccounts.add(account);
						writeToLocalTxt();
						// 注册成功后肯定要登陆下啦
						login(randomId, randomId, cookie, 0);
					} else if (resultHtml.indexOf("超过限制") != -1) {
						logger.error("当前IP注册帐号超限,请更换IP或者明天再试");
						return;
					} else {
						logger.debug("尝试注册失败，正在重新注册");
						reg();
					}
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("发生未知异常，正在重新注册");
					reg();
				} finally {
					try {
						if (response != null) {
							response.close();
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
					try {
						if (httpClient != null) {
							httpClient.close();
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				logger.debug("当前可用账号数量：" + cookieMap.size());
			}
		}
	}

	/**
	 * 登陆方法
	 * 
	 * @param regedId  帐号
	 * @param pwd      密码
	 * @param cookie   有就填，没有就新开一个连接
	 * @param tryCount 防止死循环登陆
	 * @return 当前COOKIE
	 */
	public String login(String regedId, String pwd, String cookie, int tryCount) {
		logger.debug("正在尝试登陆。。。");
		if (tryCount == 15) {
			logger.error("帐号：" + regedId + "尝试15次登陆失败，放弃");
			return null;
		}
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			Connection.Response execute = Jsoup.connect("http://lx.heikeyun.net/login.aspx").ignoreContentType(true)
					.execute();
			// 获取返回数据
			String body = execute.body();
			if (cookie == null) {
				// 获取返回cookie
				cookie = "";
				Map<String, String> cookies = execute.cookies();
				for (String key : cookies.keySet()) {
					cookie += key + "=" + cookies.get(key) + ";";
				}
			}

			Document doc = Jsoup.parse(body);
			String viewstate = doc.select("input[name=__VIEWSTATE]").val();
			String viewstategenerator = doc.select("input[name=__VIEWSTATEGENERATOR]").val();
			String eventvalidation = doc.select("input[name=__EVENTVALIDATION]").val();
			// 保持COOKIE传过去取得验证码
			String txtCode = OcrCaptchaUtil.getYzm(cookie);
			Thread.sleep(3000);
			HttpPost httpPost = new HttpPost("http://lx.heikeyun.net/login.aspx");
			httpPost.addHeader("Cookie", cookie);
			httpPost.addHeader("Host", "lx.heikeyun.net");
			httpPost.addHeader("Origin", "http://lx.heikeyun.net");
			httpPost.addHeader("Referer", "http://lx.heikeyun.net/login.aspx");
			httpPost.addHeader("Upgrade-Insecure-Requests", "1");
			httpPost.addHeader("DNT", "1");
			httpPost.addHeader("Accept-Language", "zh-CN,zh;q=0.9");
			httpPost.addHeader("Accept-Encoding", "gzip, deflate");
			httpPost.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
			httpPost.addHeader("Connection", "keep-alive");
			httpPost.addHeader("Cache-Control", "max-age=0");
			httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
			httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			nvps.add(new BasicNameValuePair("__LASTFOCUS", ""));
			nvps.add(new BasicNameValuePair("__EVENTTARGET", ""));
			nvps.add(new BasicNameValuePair("__EVENTARGUMENT", ""));
			nvps.add(new BasicNameValuePair("__VIEWSTATE", viewstate));
			nvps.add(new BasicNameValuePair("__VIEWSTATEGENERATOR", viewstategenerator));
			nvps.add(new BasicNameValuePair("__EVENTVALIDATION", eventvalidation));
			nvps.add(new BasicNameValuePair("btnLogin", "登   录"));
			nvps.add(new BasicNameValuePair("txtId", regedId));
			nvps.add(new BasicNameValuePair("txtPwd", pwd));
			nvps.add(new BasicNameValuePair("txtCode", txtCode));
			nvps.add(new BasicNameValuePair("txtRegUserName", ""));
			nvps.add(new BasicNameValuePair("txtRegPwd", ""));
			nvps.add(new BasicNameValuePair("txtRegPwd2", ""));
			nvps.add(new BasicNameValuePair("txtRegMail", ""));
			nvps.add(new BasicNameValuePair("txtRegCode", ""));
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
			response = httpClient.execute(httpPost);
			if (response.getStatusLine().getStatusCode() == 302) {
				logger.debug("尝试登陆成功！！！");
				return cookie;
			} else {
				logger.debug("尝试登陆失败，正在重新登陆");
				tryCount++;
				Thread.sleep(10000);
				return login(regedId, pwd, cookie, tryCount);
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("发生未知异常，正在重新登陆");
			tryCount++;
			return login(regedId, pwd, cookie, tryCount);
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 后台保持cookie在线
	 */
	public void keepAlive() {
		for (String cookie : cookieMap.keySet()) {
			CloseableHttpClient httpClient = null;
			CloseableHttpResponse response = null;
			try {
				httpClient = HttpClients.createDefault();
				HttpPost httpPost = new HttpPost("http://lx.heikeyun.net/Main.aspx");
				httpPost.setHeader("Cookie", cookie);
				response = httpClient.execute(httpPost);
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("保持在线状态发生错误");
			} finally {
				try {
					if (response != null) {
						response.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if (httpClient != null) {
						httpClient.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private String utf8to16(String str) {
		try {
			String out;
			int i, len, c;
			int char2, char3;
			out = "";
			len = str.length();
			i = 0;
			while (i < len) {
				c = str.charAt(i++);
				StringBuffer fileName = new StringBuffer();
				switch (c >> 4) {
				case 0:
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
				case 6:
				case 7:
					// 0xxxxxxx
					out += str.charAt(i - 1);
					break;
				case 12:
				case 13:
					// 110x xxxx 10xx xxxx
					char2 = str.charAt(i++);
					fileName.append((char) (((c & 0x1F) << 6) | (char2 & 0x3F)));
					out += fileName.toString();
					break;
				case 14:
					// 1110 xxxx 10xx xxxx 10xx xxxx
					char2 = str.charAt(i++);
					char3 = str.charAt(i++);
					fileName.append((char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)));
					out += fileName.toString();
					break;
				}
			}
			return out;
		} catch (Exception e) {
			e.printStackTrace();
			return str;
		}

	}

	/**
	 * 判断是否需要注册新号，当前有的少于设置的就补充
	 * 
	 * @return
	 */
	public boolean needReg() {
		return cookieMap.size() < maxRegUserNum;
	}

	/**
	 * 本地TXT读取帐号文件
	 */
	public void loadLocalData() {
		// 写入说明
		String shuoming = FileUtil.readString(FileUtil.touch("C:\\黑科云帐号\\说明.txt"), "gb2312");
		if ("".equals(shuoming)) {
			FileUtil.writeString("本文件是创建帐号时自动创建，如非必要请勿删除，格式请勿更改，首行是日期，下面的是帐号密码今日下载次数和是否是VIP，如自己有VIP帐号，可以修改隔壁的文本，参考格式"
					+ System.lineSeparator() + "帐号:123456密码:123456下载:0VIP:是" + System.lineSeparator()
					+ "帐号:456789密码:456789下载:5VIP:否", FileUtil.touch("C:\\黑科云帐号\\说明.txt"), "gb2312");
		}
		// 本地读取帐号密码
		List<String> zhList = FileUtil.readLines(FileUtil.touch("C:\\黑科云帐号\\黑科云帐号.txt"), "gb2312");
		if (!zhList.isEmpty()) {
			String writeDate = zhList.get(0);
			zhList.remove(0);
			String today = DateUtil.today();
			// 日期不同
			if (!today.equals(writeDate)) {
				logger.debug("文件日期和当前日期不同，清空下载次数");
				List<String> newDateTxt = new ArrayList<String>();
				newDateTxt.add(today);
				for (String zhinfo : zhList) {
					try {
						HeikeyunAccount account = HeikeyunAccount.readFromLocalString(zhinfo);
						account.setDownloadCount(0);
						heikeyunAccounts.add(account);
						canDownloadAccounts.add(account);
						newDateTxt.add(account.toLocalString());
					} catch (Exception e) {
					}
				}
				FileUtil.writeLines(newDateTxt, "C:\\黑科云帐号\\黑科云帐号.txt", "gb2312");
			} else {
				for (String zhinfo : zhList) {
					try {
						HeikeyunAccount account = HeikeyunAccount.readFromLocalString(zhinfo);
						heikeyunAccounts.add(account);
						if (account.canDownload()) {
							canDownloadAccounts.add(account);
						}
					} catch (Exception e) {
					}
				}
			}
			for (int i = 0; i < maxRegUserNum; i++) {
				HeikeyunAccount account = canDownloadAccounts.get(i);
				String cookie = login(account.getAccount(), account.getPassword(), null, 0);
				if (cookie != null) {
					cookieMap.put(cookie, account);
				}
			}
		}
	}

	/**
	 * 将List写入本地
	 */
	public void writeToLocalTxt() {
		List<String> localTxtString = new ArrayList<String>();
		List<String> zhList = FileUtil.readLines(FileUtil.touch("C:\\黑科云帐号\\黑科云帐号.txt"), "gb2312");
		if (!zhList.isEmpty()) {
			localTxtString.add(zhList.get(0));
		} else {
			localTxtString.add(DateUtil.today());
		}
		for (int i = 0; i < heikeyunAccounts.size(); i++) {
			localTxtString.add(heikeyunAccounts.get(i).toLocalString());
		}
		FileUtil.writeLines(localTxtString, "C:\\黑科云帐号\\黑科云帐号.txt", "gb2312");
	}

	/**
	 * 程序启动自动调用注册
	 */
	@Override
	public void run(String... args) throws Exception {
		loadLocalData();
		reg();
	}

}
